interface IObject {
  [k: string]: any;
}
type RemoveName = Omit<Info, "name">; // 去除 Info 类型中的 name字段
type GetName = Pick<Info, "name">; // Info 类型中值保留 name 字段
type AllPartial = Partial<Info>; // 将 Info 类型中的字段全部转成 可选字段
type AllRequired = Required<Info>; // 将 Info 类型中的字段全部转成 必选字段

/**
 * 工具函数一
 * 合并 T 和 R 两个对象
 */
type MergeObject<T extends IObject, R extends IObject> = {
  [K in keyof T | keyof R]: K extends keyof T
    ? T[K]
    : K extends keyof R
    ? R[K]
    : never;
};

interface Info {
  name: string;
  age: number;
  color?: string;
}
interface IFirend {
  has: boolean;
  info?: IObject;
}

type FirendInfo = MergeObject<Info, IFirend>;

interface IObj {
  name: string;
  age: number;
  vac01: string;
}

interface IPer {
  name?: string;
  age: number;
  vae01: string;
}
type KeyT = keyof IObj;
const temp: KeyT = "name";
temp;

export type PublicOwnObject1<
  T extends Record<string, any>,
  P extends Record<string, any>
> = {
  // [K in keyof T & keyof P]: undefined extends T[K] | P[K] ? undefined | T[K] | P[K] : T[K] extends P[K] ? T[K] : P[K] | T[K];
  // [K in keyof T & keyof P]: T[K] | P[K];
  [K in keyof T & keyof P]: undefined extends T[K] | P[K] ? K : never;
}[keyof T & keyof P];

export type PublicOwnObject2<
  T extends Record<string, any>,
  P extends Record<string, any>
> = {
  // [K in keyof T & keyof P]: undefined extends T[K] | P[K] ? undefined | T[K] | P[K] : T[K] extends P[K] ? T[K] : P[K] | T[K];
  // [K in keyof T & keyof P]: T[K] | P[K];
  [K in keyof T & keyof P]: undefined extends T[K] | P[K] ? never : K;
}[keyof T & keyof P];

type PublicOwnObjectUni<
  T extends Record<string, any>,
  P extends Record<string, any>
> = {
  [K in PublicOwnObject1<T, P>]?: T[K] | P[K];
};
type PublicOwnObjectReq<
  T extends Record<string, any>,
  P extends Record<string, any>
> = {
  [K in PublicOwnObject2<T, P>]: T[K] | P[K];
};

type Test1 = PublicOwnObject1<IObj, IPer>; // 获取可选key
type Test2 = PublicOwnObject2<IObj, IPer>; // 获取必选的key
type TestP = PublicOwnObjectUni<IObj, IPer>; // 提取 可选key的类型对象 {key?: string | number }
type TestR = PublicOwnObjectReq<IObj, IPer>; // 提取 必填key的类型对象

// 怎么得到 TargetType 类型？
type TargetType = {
  name?: string;
  age: number;
};

interface IKoa {
  name: string;
  info?: boolean;
  age?: number;
}

// type MergeType<T extends IObject, P extends IObject> = { ...T }

/**
 * 获取对象类型中的可选属性，返回一个新的对象类型
 */
type GetOptional<T> = {
  [P in keyof T as T[P] extends Required<T>[P] ? never : P]: T[P];
};

/**
 * 只保留T对象类型中的必填字段
 */
type GetRequired<T> = {
  [P in keyof T as T[P] extends Required<T>[P] ? P : never]: T[P];
};

type M = Required<IKoa>;
type M1 = Partial<IKoa>;
type F1 = GetOptional<IKoa>;
type R = GetRequired<IKoa>;

// ===>>> 使用 -?  ? 合并对象 可选？

type Merge<T, M> = {
  [P in keyof T | keyof M]: P extends keyof T
    ? P extends keyof M
      ? T[P] | M[P]
      : T[P]
    : P extends keyof M
    ? M[P]
    : never;
};

type U = Merge<IObj, IPer>;

/**
 * 将 T 对象类型中的 某个字段变成可选字段
 */
type SetOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
type O1 = SetOptional<IObj, "name">;
const o: O1 = {
  // name: "1",
  age: 2,
  vac01: "11",
};

type OptionalPropertyNames<T> = {
  [K in keyof T]: undefined extends T[K] ? K : never;
}[keyof T];

// Common properties from L and R with undefined in R[K] replaced by type in L[K]
type SpreadProperties<L, R, K extends keyof L & keyof R> = {
  [P in K]: L[P] | Exclude<R[P], undefined>;
};

type Id<T> = T extends infer U ? { [K in keyof U]: U[K] } : never; // see note at bottom*

/**
 * 合并两个对象类型，两个对象类型L，P中，只有一边有对的字段，且是可选的，最终会变成可选
 * { A: string } { B?: number } --> { A: string; B?: number | undefined }
 * { A: string; B: number } { B?: number } --> { A: string; B: number }
 */
// Type of { ...L, ...R }
type Spread<L, R> = Id<
  // Properties in L that don't exist in R
  Pick<L, Exclude<keyof L, keyof R>> &
    // Properties in R with types that exclude undefined
    Pick<R, Exclude<keyof R, OptionalPropertyNames<R>>> &
    // Properties in R, with types that include undefined, that don't exist in L
    Pick<R, Exclude<OptionalPropertyNames<R>, keyof L>> &
    // Properties in R, with types that include undefined, that exist in L
    SpreadProperties<L, R, OptionalPropertyNames<R> & keyof L>
>;

interface IA {
  A: string;
  B?: string;
}
interface IB {
  B?: string;
}

type H = Spread<Info, IKoa>;
type H1 = Spread<IA, IB>;

/**
 * 工具类
 * 类型取反
 */
type BandType<T, P> = T extends P ? never : T;

type B1 = BandType<2, string>; // 2
type B2 = BandType<"1", string>; // never

// 使用场景：定义一个函数 参数不能是string 类型，除string类型外其他类型都可以
function fn<T>(m: BandType<T, string>) {}
fn(1); // 正确
// fn("1") // 报错
export {};
